﻿using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using SimpleCmsWithAbp.Authorization;
using SimpleCmsWithAbp.Categories.Dto;
using SimpleCmsWithAbp.Contents.Dto;
using SimpleCmsWithAbp.Helper;
using SimpleCmsWithAbp.Tags;

namespace SimpleCmsWithAbp.Contents
{
    [AbpAuthorize(PermissionNames.Pages_Articles)]
    public class ContentAppService: AsyncCrudAppService<Content, ContentDto, long>, IContentAppService
    {
        private readonly IRepository<Tag,long> _tagsRepository;
        private readonly IRepository<ContentTag, long> _contentTagRepository;

        public ContentAppService(IRepository<Content, long> repository, IRepository<Tag, long> tagsRepository,
            IRepository<ContentTag, long> contentTagRepository) : base(repository)
        {
            _tagsRepository = tagsRepository;
            _contentTagRepository = contentTagRepository;
        }



        [ActionName(nameof(GetAll))]
        public async Task<PagedResultDto<GetAllContentOutputDto>> GetAll(GetAllContentInputDto input)
        {
            CheckGetAllPermission();

            var query = Repository.GetAllIncluding(m => m.Category).Include(m=>m.ContentTags).AsQueryable();

            if (input.Cid > 0) query = query.Where(m => m.CategoryId == input.Cid);
            if (!string.IsNullOrEmpty(input.Query))
                query = query.Where(m =>
                    m.Title.Contains(input.Query) || m.Summary.Contains(input.Query) || m.Body.Contains(input.Query));
            if (input.StartDateTime != null) query = query.Where(m => m.CreationTime > input.StartDateTime);
            if (input.EndDateTime != null) query = query.Where(m => m.CreationTime < input.EndDateTime);

            var totalCount = await AsyncQueryableExecuter.CountAsync(query);

            query = ApplySorting(query, input);
            query = ApplyPaging(query, input);

            var entities = await AsyncQueryableExecuter.ToListAsync(query);
            return new PagedResultDto<GetAllContentOutputDto>(
                totalCount,
                entities.Select(MapToGetAllContentOutputDto).ToList()
            );

        }

        public GetAllContentOutputDto MapToGetAllContentOutputDto(Content content)
        {
            var map = ObjectMapper.Map<GetAllContentOutputDto>(content);
            map.CategoryTitle = content.Category.Title;
            map.Tags = _tagsRepository.GetAll().Where(m => content.ContentTags.Select(n => n.TagId).Contains(m.Id)).Select(m=>m.Name).ToArray();
            //map.Tags = content.ContentTags.Select(m => m.Tag.Name).ToList();
            return map;
        }

        [ActionName(nameof(Create))]
        public async Task<ContentDto> Create(CreateContentDto input)
        {
            CheckCreatePermission();
            var entity = ObjectMapper.Map<Content>(input);
            entity.TenantId = AbpSession.TenantId ?? 1;
            entity.CreatorUserId = AbpSession.UserId;
            await Repository.InsertAsync(entity);
            await CurrentUnitOfWork.SaveChangesAsync();
            await AddTags(input.Tags, entity);
            return MapToEntityDto(entity);

        }

        private async Task AddTags(string[] inputTags, Content entity)
        {
            var tags = _tagsRepository.GetAll().Where(m => inputTags.Contains(m.Name));
            foreach (var tag in tags)
            {
                await _contentTagRepository.InsertAsync(new ContentTag()
                {
                    Content = entity,
                    Tag = tag
                });
            }

        }

        [ActionName(nameof(Update))]
        public async Task<ContentDto> Update(UpdateContentDto input)
        {
            CheckUpdatePermission();
            var entity = ObjectMapper.Map<Content>(input);
            entity.LastModifierUserId = AbpSession.UserId;
            await Repository.UpdateAsync(entity);
            var tags = _contentTagRepository.GetAll().Where(m => m.ContentId == entity.Id);
            foreach (var contentTag in tags)
            {
                await _contentTagRepository.DeleteAsync(contentTag.Id);
            }
            await AddTags(input.Tags, entity);
            await CurrentUnitOfWork.SaveChangesAsync();

            return MapToEntityDto(entity);
        }

        public async Task Delete(DeleteContentInputDto input)
        {
            CheckDeletePermission();
            foreach (var inputId in input.Id)
            {
                await Repository.DeleteAsync(inputId);
            }
        }

        [NonAction]
        public override Task<PagedResultDto<ContentDto>> GetAll(PagedAndSortedResultRequestDto input)
        {
            return base.GetAll(input);
        }

        [NonAction]
        public override Task<ContentDto> Create(ContentDto input)
        {
            return base.Create(input);
        }

        [NonAction]
        public override Task<ContentDto> Update(ContentDto input)
        {
            return base.Update(input);
        }

        [NonAction]
        public override Task Delete(EntityDto<long> input)
        {
            return base.Delete(input);
        }
    }
}